<template>
  <teleport to="body">
    <!-- 开发环境下的错误球 -->
    <transition name="error-ball-fade">
      <div
        v-if="isDev && errorCount > 0"
        ref="errorBallRef"
        class="error-ball"
        :class="{ 'is-dragging': isDragging }"
        :style="ballPosition"
        @mousedown="startDrag"
        @touchstart="startDrag"
        @click="handleBallClick"
      >
        <!-- 错误数量显示 -->
        <div class="error-count">
          {{ displayCount }}
        </div>

        <!-- 错误类型指示器 -->
        <div class="error-indicator" :class="errorLevelClass">
          <el-icon><Warning /></el-icon>
        </div>
      </div>
    </transition>

    <!-- 错误列表弹窗 -->
    <transition name="error-list-slide">
      <div v-if="showErrorList" class="error-list-modal" @click="handleBackdropClick">
        <div class="error-list-content" @click.stop>
          <div class="error-list-header">
            <div class="header-left">
              <h3>错误记录列表</h3>
              <span class="total-count">共 {{ errorQueue.length }} 条</span>
            </div>
            <div class="header-actions">
              <el-button @click="refreshErrorList" size="small" plain>
                <el-icon><Refresh /></el-icon>
                刷新
              </el-button>
              <el-button @click="clearAllErrors" size="small" plain>
                <el-icon><Delete /></el-icon>
                清空
              </el-button>
              <el-button @click="closeErrorList" size="small" class="close-button">
                <el-icon><Close /></el-icon>
              </el-button>
            </div>
          </div>

          <div class="error-list-body">
            <div v-if="errorQueue.length === 0" class="empty-state">
              <el-icon class="empty-icon"><InfoFilled /></el-icon>
              <p>暂无错误记录</p>
            </div>

            <div v-else class="error-items">
              <!-- 分页显示 -->
              <div
                v-for="(error, index) in paginatedErrors"
                :key="`${error.timestamp}-${index}`"
                class="error-item"
                @click="showErrorDetail(error, currentPage * pageSize + index)"
              >
                <div class="error-item-header">
                  <div class="error-type-badge" :class="getErrorTypeClass(error.type)">
                    {{ error.type }}
                  </div>
                  <div class="error-time">
                    {{ formatTime(error.timestamp) }}
                  </div>
                </div>

                <div class="error-message">
                  {{ truncateMessage(error.message, 100) }}
                </div>

                <div class="error-item-footer">
                  <span class="error-location" v-if="error.url">
                    {{ getFileName(error.url) }}
                    <template v-if="error.line">:{{ error.line }}</template>
                  </span>
                  <el-icon class="detail-arrow"><ArrowRight /></el-icon>
                </div>
              </div>
            </div>

            <!-- 分页组件 -->
            <div v-if="totalPages > 1" class="error-pagination">
              <el-pagination
                v-model:current-page="currentPage"
                v-model:page-size="pageSize"
                :page-sizes="[5, 10, 20, 50]"
                :total="errorQueue.length"
                layout="total, sizes, prev, pager, next"
                small
                background
              />
            </div>
          </div>
        </div>
      </div>
    </transition>

    <!-- 错误详情弹窗 -->
    <GlobalErrorModal
      :visible="showErrorDetailModal"
      :error-info="selectedError"
      @close="closeErrorDetail"
      @reload="handleReload"
    />
  </teleport>
</template>

<script setup lang="ts">
  import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue';
  import { ElMessage } from 'element-plus';
  import { Warning, Delete, Close, InfoFilled, ArrowRight, Refresh } from '@element-plus/icons-vue';
  import { globalErrorHandler, type ErrorInfo } from '@/utils/errorHandler';
  import GlobalErrorModal from './index.vue';

  // 开发环境检测
  const isDev = ref(import.meta.env.DEV);

  // 响应式状态
  const errorBallRef = ref<HTMLElement>();
  const errorQueue = ref<ErrorInfo[]>([]);
  const showErrorList = ref(false);
  const showErrorDetailModal = ref(false);
  const selectedError = ref<ErrorInfo>({
    message: '',
    timestamp: Date.now(),
    type: '',
  });

  // 分页相关状态
  const currentPage = ref(1);
  const pageSize = ref(10);

  // 拖拽相关状态
  const isDragging = ref(false);
  const hasDragged = ref(false); // 标记是否发生了拖拽
  const ballPosition = ref({
    right: '20px',
    bottom: '80px',
    left: 'auto',
    top: 'auto',
  });

  const dragOffset = ref({ x: 0, y: 0 });

  // 计算属性
  const errorCount = computed(() => errorQueue.value.length);

  const displayCount = computed(() => {
    return errorCount.value > 99 ? '99+' : errorCount.value.toString();
  });

  const errorLevelClass = computed(() => {
    const hasError = errorQueue.value.some(
      (e) => e.type.includes('Error') && !e.type.includes('Warning'),
    );
    const hasWarning = errorQueue.value.some((e) => e.type.includes('Warning'));

    if (hasError) return 'error-level-high';
    if (hasWarning) return 'error-level-medium';
    return 'error-level-low';
  });

  // 分页计算属性
  const totalPages = computed(() => Math.ceil(errorQueue.value.length / pageSize.value));

  const paginatedErrors = computed(() => {
    const start = (currentPage.value - 1) * pageSize.value;
    const end = start + pageSize.value;
    return errorQueue.value.slice(start, end);
  });

  // 更新错误队列
  const updateErrorQueue = () => {
    try {
      const newQueue = globalErrorHandler.getErrorQueue();
      // 确保获取到有效的数组
      if (Array.isArray(newQueue)) {
        errorQueue.value = [...newQueue]; // 创建新数组以触发响应式更新
      } else {
        console.warn('Invalid error queue received:', newQueue);
        errorQueue.value = [];
      }
    } catch (error) {
      console.error('Error updating error queue:', error);
      // 降级处理，不影响组件正常运行
      errorQueue.value = [];
    }
  };

  // 格式化时间
  const formatTime = (timestamp: number) => {
    const now = Date.now();
    const diff = now - timestamp;

    if (diff < 60000) return '刚刚';
    if (diff < 3600000) return `${Math.floor(diff / 60000)}分钟前`;
    if (diff < 86400000) return `${Math.floor(diff / 3600000)}小时前`;

    return new Date(timestamp).toLocaleString('zh-CN');
  };

  // 截断消息
  const truncateMessage = (message: string, maxLength: number) => {
    if (message.length <= maxLength) return message;
    return message.slice(0, maxLength) + '...';
  };

  // 获取文件名
  const getFileName = (url: string) => {
    try {
      return url.split('/').pop()?.split('?')[0] || url;
    } catch {
      return url;
    }
  };

  // 获取错误类型样式类
  const getErrorTypeClass = (type: string) => {
    if (type.includes('Error') && !type.includes('Warning')) {
      return 'error-type-error';
    }
    if (type.includes('Warning')) {
      return 'error-type-warning';
    }
    if (type.includes('Network')) {
      return 'error-type-network';
    }
    return 'error-type-info';
  };

  // 获取错误项样式类
  const getErrorItemClass = (type: string) => {
    return `error-item-${getErrorTypeClass(type).replace('error-type-', '')}`;
  };

  // 拖拽功能
  const startDrag = (event: MouseEvent | TouchEvent) => {
    if (!errorBallRef.value) return;

    event.preventDefault();
    event.stopPropagation(); // 防止触发点击事件
    isDragging.value = true;
    hasDragged.value = false; // 重置拖拽标志

    const clientX = event instanceof MouseEvent ? event.clientX : event.touches[0].clientX;
    const clientY = event instanceof MouseEvent ? event.clientY : event.touches[0].clientY;

    const rect = errorBallRef.value.getBoundingClientRect();
    dragOffset.value = {
      x: clientX - rect.left,
      y: clientY - rect.top,
    };

    // 添加被动监听器选项
    document.addEventListener('mousemove', handleDrag, { passive: false });
    document.addEventListener('mouseup', stopDrag);
    document.addEventListener('touchmove', handleDrag, { passive: false });
    document.addEventListener('touchend', stopDrag);
  };

  const handleDrag = (event: MouseEvent | TouchEvent) => {
    if (!isDragging.value) return;

    event.preventDefault();
    hasDragged.value = true; // 标记发生了拖拽

    const clientX = event instanceof MouseEvent ? event.clientX : event.touches[0].clientX;
    const clientY = event instanceof MouseEvent ? event.clientY : event.touches[0].clientY;

    const newX = clientX - dragOffset.value.x;
    const newY = clientY - dragOffset.value.y;

    // 限制拖拽范围
    const maxX = window.innerWidth - 60;
    const maxY = window.innerHeight - 60;

    const constrainedX = Math.max(0, Math.min(newX, maxX));
    const constrainedY = Math.max(0, Math.min(newY, maxY));

    ballPosition.value = {
      left: `${constrainedX}px`,
      top: `${constrainedY}px`,
      right: 'auto',
      bottom: 'auto',
    };
  };

  const stopDrag = () => {
    if (!isDragging.value) return;

    isDragging.value = false;
    document.removeEventListener('mousemove', handleDrag);
    document.removeEventListener('mouseup', stopDrag);
    document.removeEventListener('touchmove', handleDrag);
    document.removeEventListener('touchend', stopDrag);

    // 吸边效果
    nextTick(() => {
      if (!errorBallRef.value) return;

      const rect = errorBallRef.value.getBoundingClientRect();
      const centerX = rect.left + rect.width / 2;
      const shouldStickToRight = centerX > window.innerWidth / 2;

      if (shouldStickToRight) {
        ballPosition.value = {
          right: '20px',
          top: `${Math.max(20, rect.top)}px`,
          left: 'auto',
          bottom: 'auto',
        };
      } else {
        ballPosition.value = {
          left: '20px',
          top: `${Math.max(20, rect.top)}px`,
          right: 'auto',
          bottom: 'auto',
        };
      }
    });

    // 延迟一段时间后重置拖拽状态
    setTimeout(() => {
      isDragging.value = false;
      // hasDragged 保持状态，用于判断是否应该触发点击
    }, 50);
  };

  // 处理错误球点击事件
  const handleBallClick = (event: MouseEvent) => {
    try {
      event.stopPropagation();

      // 如果刚刚拖拽过，不触发点击
      if (hasDragged.value) {
        hasDragged.value = false; // 重置标志
        return;
      }

      toggleErrorList();
    } catch (error) {
      console.error('Error in handleBallClick:', error);
      // 降级处理，确保用户仍然可以操作
      showErrorList.value = !showErrorList.value;
    }
  };

  // 错误列表相关功能
  const toggleErrorList = () => {
    showErrorList.value = !showErrorList.value;
    if (showErrorList.value) {
      currentPage.value = 1; // 重置到第一页
      updateErrorQueue();
    }
  };

  const closeErrorList = () => {
    try {
      showErrorList.value = false;
      currentPage.value = 1; // 重置页面
    } catch (error) {
      console.error('Error in closeErrorList:', error);
      // 强制关闭
      showErrorList.value = false;
    }
  };

  const handleBackdropClick = (event: MouseEvent) => {
    try {
      // 只有点击背景时才关闭，避免误触
      if (event.target === event.currentTarget) {
        closeErrorList();
      }
    } catch (error) {
      console.error('Error in handleBackdropClick:', error);
      // 降级处理
      showErrorList.value = false;
    }
  };

  // 错误详情相关功能
  const showErrorDetail = (error: ErrorInfo, index: number) => {
    selectedError.value = error;
    showErrorDetailModal.value = true;
    showErrorList.value = false; // 关闭列表，显示详情
  };

  const closeErrorDetail = () => {
    showErrorDetailModal.value = false;
  };

  const handleReload = () => {
    closeErrorDetail();
    window.location.reload();
  };

  // 刷新错误列表
  const refreshErrorList = () => {
    try {
      updateErrorQueue();
      ElMessage.success('已刷新错误列表');
    } catch (error) {
      console.error('刷新错误列表失败:', error);
      ElMessage.error('刷新失败，请重试');
    }
  };

  // 清空所有错误
  const clearAllErrors = () => {
    try {
      globalErrorHandler.clearErrorQueue();
      // 立即更新本地状态
      errorQueue.value = [];
      ElMessage.success('已清空所有错误记录');
      closeErrorList();
    } catch (error) {
      console.error('清空错误失败:', error);
      ElMessage.error('清空失败，请重试');
      // 尝试恢复状态
      updateErrorQueue();
    }
  };

  // 定期更新错误队列
  let updateInterval: number;

  onMounted(() => {
    updateErrorQueue();
    updateInterval = window.setInterval(updateErrorQueue, 500); // 更频繁的更新
  });

  onUnmounted(() => {
    if (updateInterval) {
      clearInterval(updateInterval);
    }

    // 清理拖拽事件监听器
    document.removeEventListener('mousemove', handleDrag);
    document.removeEventListener('mouseup', stopDrag);
    document.removeEventListener('touchmove', handleDrag);
    document.removeEventListener('touchend', stopDrag);
  });
</script>

<style lang="scss" scoped>
  // 错误球样式 - 管理后台风格
  .error-ball {
    position: fixed;
    width: 52px;
    height: 52px;
    border-radius: 8px;
    background: #909399;
    border: 2px solid #dcdfe6;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
    cursor: grab;
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    user-select: none;
    transition: all 0.2s ease;

    &:hover {
      background: #606266;
      border-color: #c0c4cc;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
    }

    &.is-dragging {
      cursor: grabbing;
      box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
      transition: none;
    }
  }

  .error-count {
    position: absolute;
    top: -6px;
    right: -6px;
    background: #e6a23c;
    color: #fff;
    border-radius: 10px;
    padding: 2px 5px;
    font-size: 11px;
    font-weight: 600;
    min-width: 18px;
    text-align: center;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
    line-height: 1.2;
  }

  .error-indicator {
    font-size: 20px;
    color: #fff;
  }

  // 错误球动画
  .error-ball-fade-enter-active,
  .error-ball-fade-leave-active {
    transition: all 0.3s ease;
  }

  .error-ball-fade-enter-from,
  .error-ball-fade-leave-to {
    opacity: 0;
    transform: scale(0.5);
  }

  // 错误列表弹窗样式 - 管理后台风格
  .error-list-modal {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.3);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10000;
    padding: 20px;
  }

  .error-list-content {
    background: #fff;
    border-radius: 4px;
    border: 1px solid #dcdfe6;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
    max-width: 900px;
    width: 100%;
    max-height: 80vh;
    display: flex;
    flex-direction: column;
  }

  .error-list-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 16px 20px;
    border-bottom: 1px solid #e4e7ed;
    background: #f5f7fa;

    .header-left {
      display: flex;
      align-items: center;
      gap: 12px;
    }

    h3 {
      margin: 0;
      font-size: 16px;
      font-weight: 500;
      color: #303133;
    }

    .total-count {
      font-size: 12px;
      color: #909399;
      background: #e4e7ed;
      padding: 2px 8px;
      border-radius: 10px;
    }

    .header-actions {
      display: flex;
      align-items: center;
      gap: 8px;
    }

    .close-button {
      border: none;
      background: none;

      &:hover {
        background: #e4e7ed;
      }
    }
  }

  .error-list-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
  }

  .empty-state {
    text-align: center;
    padding: 40px 20px;
    color: #909399;

    .empty-icon {
      font-size: 32px;
      margin-bottom: 12px;
      opacity: 0.6;
    }

    p {
      margin: 0;
      font-size: 14px;
    }
  }

  .error-items {
    flex: 1;
    overflow-y: auto;
    min-height: 200px;
  }

  .error-pagination {
    padding: 16px 20px;
    border-top: 1px solid #e4e7ed;
    background: #fafafa;
    display: flex;
    justify-content: center;
  }

  .error-item {
    padding: 12px 20px;
    border-bottom: 1px solid #ebeef5;
    cursor: pointer;
    transition: all 0.2s;
    position: relative;

    &:hover {
      background: #f5f7fa;
    }

    &:last-child {
      border-bottom: none;
    }
  }

  .error-item-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 8px;
  }

  .error-type-badge {
    padding: 2px 6px;
    border-radius: 2px;
    font-size: 11px;
    font-weight: 500;
    color: #fff;

    &.error-type-error {
      background: #f56c6c;
    }

    &.error-type-warning {
      background: #e6a23c;
    }

    &.error-type-network {
      background: #409eff;
    }

    &.error-type-info {
      background: #909399;
    }
  }

  .error-time {
    font-size: 11px;
    color: #c0c4cc;
  }

  .error-message {
    font-size: 13px;
    color: #606266;
    line-height: 1.4;
    margin-bottom: 6px;
    word-break: break-word;
  }

  .error-item-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;

    .error-location {
      font-size: 11px;
      color: #c0c4cc;
      font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
    }

    .detail-arrow {
      color: #dcdfe6;
      font-size: 12px;
      transition: all 0.2s;
    }
  }

  .error-item:hover .detail-arrow {
    color: #909399;
    transform: translateX(2px);
  }

  // 列表滑入动画
  .error-list-slide-enter-active,
  .error-list-slide-leave-active {
    transition: all 0.3s ease;
  }

  .error-list-slide-enter-from,
  .error-list-slide-leave-to {
    opacity: 0;
    transform: scale(0.9) translateY(-20px);
  }

  // 响应式设计
  @media (max-width: 768px) {
    .error-ball {
      width: 50px;
      height: 50px;

      .error-indicator {
        font-size: 20px;
      }
    }

    .error-count {
      top: -6px;
      right: -6px;
      font-size: 11px;
    }

    .error-list-modal {
      padding: 10px;
    }

    .error-list-content {
      max-height: 90vh;
    }

    .error-list-header {
      padding: 16px;

      h3 {
        font-size: 16px;
      }
    }

    .error-item {
      padding: 12px 16px;
    }

    .error-message {
      font-size: 13px;
    }
  }

  // 平板适配
  @media (max-width: 1024px) and (min-width: 769px) {
    .error-list-content {
      max-width: 90%;
    }
  }
</style>
